﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WinFormsGraphicsDevice;
using TinyEngine.Core.Scene;
using TinyEngine.Core.Services;
using Microsoft.Xna.Framework;
using TinyEngine.Core.Camera;
using TinyEngine.Core;
using TinyEngine.Core.Renderer;
using Microsoft.Xna.Framework.Graphics;
using TinyEngine.Editor.Extensibility;

namespace TinyEngineEditor.SceneViewer
{
    class SceneViewerGraphicsControl : BasicGraphicsDeviceControl
    {
        BasicCamera camera;
        IEntity selectedItem;
        
        public SceneViewerGraphicsControl()
        {
            camera = new BasicCamera();
            camera.Zoom = 1;
            camera.Position = Vector3.Zero;
            camera.ViewPortSize = new Point(this.Width, this.Height);
            
            
        }
        public void SetZoom(float zoom)
        {
            camera.Zoom = zoom;
            camera.UpdateTransform();
            this.Invalidate();
        }
        public void MoveCamera(Vector3 vec)
        {
            camera.Position = vec;
            camera.UpdateTransform();
            this.Invalidate();
        }
        
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            camera.ViewPortSize = new Point(this.Width, this.Height);
            camera.UpdateTransform();
        }

        protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
        {
            base.OnMouseDown(e);
            this.Invalidate();

            if (EditorSession.Instance.sceneManager == null ||
                EditorSession.Instance.sceneManager.ActiveGameScene == null)
                return;

            IEntity itemSelected = null;
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                //Find an item
                var pos = camera.Position;
                pos.X += e.X;
                pos.Y += e.Y;
                pos.X -= camera.Pivot.X;
                pos.Y -= camera.Pivot.Y;
                IEntity itemFound = null;
                if (EditorSession.Instance.sceneManager != null)
                {
                    var scene = EditorSession.Instance.sceneManager.ActiveGameScene;

                    foreach (var item in scene.Graph.FindEntitiesAtPosition(pos.ToVector2()))
                    {
                        //itemSelected = item;
                        if (itemFound != null)
                        {
                            if (item.Position.Z < itemFound.Position.Z)
                                itemFound = item;
                            else if (item.Position.Z == itemFound.Position.Z)
                            {
                                if (item.BoundingRectangle.Width < itemFound.BoundingRectangle.Width &&
                                    item.BoundingRectangle.Height < itemFound.BoundingRectangle.Height)
                                {
                                    itemFound = item;
                                }
                            }
                        }
                        else
                            itemFound = item;

                        
                    }
                    if (itemFound != null)
                        itemSelected = itemFound;

                    if (itemSelected != null && itemSelected != selectedItem)
                    {
                        selectedItem = itemSelected;
                        EditorSession.Instance.SetSelectedItem(selectedItem);
                    }

                    Invalidate();
                }
            }
        }

        public void Reset()
        {
            selectedItem = null;

            Invalidate();
        }
        
        protected override void Draw()
        {

            var sm = EditorSession.Instance.sceneManager;
            if (sm != null && sm.ActiveGameScene != null)
            {
                var engine = ServiceManager.GetService<TinyEngine.Core.Services.TinyGameEngine>();
                var rt = ServiceManager.GetService<RenderTargetService>();

                DrawSceneToMainRenderTarget(engine);

                base.Draw();

                engine.DrawScene(new GameTime(), sm.ActiveGameScene, camera, false);

                var sb = ServiceManager.GetService<SpriteBatchService>();
                var cam = sm.ActiveGameScene.FirstCamera;

                DrawOverlayTransparency(sb);

                DrawSceneFullOpacity(rt, sb, cam);

                if (selectedItem != null)
                {
                    PrimitiveBatchService serv = ServiceManager.GetService<PrimitiveBatchService>();
                    serv.Batch.SetTransform(camera.Transform);
                    serv.Batch.DrawBox(selectedItem.BoundingRectangle, Color.Yellow);
                }
            }
            else
                base.Draw();

            
        }

        private void DrawSceneFullOpacity(RenderTargetService rt, SpriteBatchService sb, ICamera cam)
        {
            
            sb.Batch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, camera.Transform);
            sb.Batch.Draw(rt.RawScene, cam.Position.ToVector2(), null,
                Color.White,
                0,
                new Vector2(rt.RawScene.Width / 2, rt.RawScene.Height / 2),
                1, SpriteEffects.None, 0);
            sb.Batch.End();
        }

        private void DrawOverlayTransparency(SpriteBatchService sb)
        {
            if (DefaultTexture != null)
            {
                sb.Batch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, camera.Transform);
                var width = sb.Batch.GraphicsDevice.Viewport.Width / 2;
                var height = sb.Batch.GraphicsDevice.Viewport.Height / 2;
                sb.Batch.Draw(
                    DefaultTexture,
                    new Rectangle(-width, -height,
                        width * 2, height * 2),
                        Color.Black * 0.5f);
                sb.Batch.End();
            }

        }

        private void DrawSceneToMainRenderTarget(TinyGameEngine engine)
        {
            var rt = ServiceManager.GetService<RenderTargetService>();
            var sm = EditorSession.Instance.sceneManager;

            if (rt.RawScene == null)
                return;


            var sb = ServiceManager.GetService<SpriteBatchService>();
            var cam = sm.ActiveGameScene.FirstCamera;
            ((Basic2DCamera)cam).UpdateTransform();
            engine.DrawScene(new GameTime(), sm.ActiveGameScene, cam);

        }
    }
}
